package com.mfoyou.agent.web.utils.redis;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.mfoyou.agent.utils.common.MfoyouMap;
import org.mfoyou.agent.utils.common.StrUtil;

import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;

/**
 * Redis 缓存管理类
 *
 * @author hzhang7
 */
public class RedisCacheManger {

    private static final Logger logger = Logger.getLogger(RedisCacheManger.class);

    /**
     * 分布式 jedis 池 - 通过 applicationContext.xml 注入
     */
    private ShardedJedisPool pool;

    public ShardedJedisPool getPool() {
        return pool;
    }

    public void setPool(ShardedJedisPool pool) {
        this.pool = pool;
    }

    /**
     * 从 jedis pool 取出 jedis
     *
     * @return
     */
    public ShardedJedis getRedis() {
        ShardedJedis jedis = pool.getResource();
        if (jedis == null) {
            logger.error("jedis is null");
        }
        return jedis;
    }

    /**
     *  释放 jedis
     *
     * @param jedis
     */
    public void releaseRedis(ShardedJedis jedis) {
        jedis.close();
    }

    /**
     * 根据 key 获取 redis 缓存信息
     *
     * @param key
     * @return
     */
    public String getValue(String key) {
        ShardedJedis jedis = pool.getResource();
        String ret = null;
        try {
            ret = jedis.get(key);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return ret;
    }

    /**
     * redis 存储信息
     *
     * @param key
     * @param value
     * @param seconds
     * @return
     */
    public boolean setValue(String key, String value, int seconds) {
        ShardedJedis jedis = pool.getResource();
        try {
            ShardedJedisPipeline shardedJedisPipeline = jedis.pipelined();
            shardedJedisPipeline.set(key, value);
            shardedJedisPipeline.expire(key, seconds);
            shardedJedisPipeline.sync();
        } catch (Exception e) {

            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;

        }
        jedis.close();
        return true;
    }

    /**
     * redis 存储信息
     *
     * @param key
     * @param value
     * @param seconds
     * @return
     */
    public boolean setValue(String key, Integer value, int seconds) {
        return setValue(key, "" + value, seconds);
    }

    /**
     * 根据 key 获取 redis 缓存信息
     *
     * @param key
     * @return
     */
    public Map<String, String> getMapValue(String key) {
        ShardedJedis jedis = pool.getResource();
        Map<String, String> map = null;
        try {
            map = jedis.hgetAll(key);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return map;
    }

    /**
     * 存储信息到 redis 缓存中
     *
     * @param key
     * @param map
     * @param seconds
     * @return
     */
    public boolean setMapValue(String key, Map<String, String> map, int seconds) {
        MfoyouMap.removeNullValue(map);
        if (map.size() == 0) {
            return true;
        }
        ShardedJedis jedis = pool.getResource();
        try {
            jedis.hmset(key, map);
            jedis.expire(key, seconds);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;
        }
        jedis.close();
        return true;
    }

    /**
     * redis 存储信息
     *
     * @param mainKey
     * @param mapKey
     * @param value
     * @param seconds
     * @return
     */
    public boolean setMapKeyValue(String mainKey, String mapKey, String value, Integer seconds) {
        if (mainKey == null || mapKey == null || value == null){ return false;}
        ShardedJedis jedis = pool.getResource();
        try {
            jedis.hset(mainKey, mapKey, value);
            if (seconds != null) jedis.expire(mainKey, seconds);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;
        }
        jedis.close();
        return true;
    }

    public boolean IncMapKeyValue(String mainKey, String mapKey, Integer incValue, Integer seconds) {
        ShardedJedis jedis = pool.getResource();
        try {
            jedis.hincrBy(mainKey, mapKey, incValue);
            if (seconds != null) jedis.expire(mainKey, seconds);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;
        }
        jedis.close();
        return true;
    }

    /**
     * 清除 redis 信息
     *
     * @param key
     * @return
     */
    public boolean deleteKey(String key) {
        ShardedJedis jedis = pool.getResource();
        logger.info("deleteKey:" + key);
        try {
            jedis.del(key);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;

        }
        jedis.close();
        return true;
    }

    /**
     * 集群，分片模式下不能使用此函数不然会有问题的
     *
     * @param pattern
     * @return
     */
    @Deprecated
    public Set<String> keys(String pattern) {
        Set<String> set = null;
        ShardedJedis jedis = pool.getResource();
        try {
            set = jedis.getShard(pattern).keys(pattern);
        } catch (Exception e) {

            logger.error("", e);
            jedis.close();
            return new HashSet<>();

        }
        jedis.close();
        return set;
    }

    /**
     * 设置指定 key 的过期时间
     * @param key
     * @param seconds
     * @return
     */
    public boolean setExpire(String key, int seconds) {
        ShardedJedis jedis = pool.getResource();
        try {
            jedis.expire(key, seconds);
        } catch (Exception e) {

            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;

        }
        jedis.close();
        return true;
    }

    public boolean exists(String key) {
        ShardedJedis jedis = pool.getResource();
        boolean bret = false;
        try {
            bret = jedis.exists(key);

        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
            jedis.close();
            return false;

        }
        jedis.close();
        return bret;
    }

    public Long getIncr(String key) {
        ShardedJedis jedis = pool.getResource();
        Long ret = null;
        try {
            ret = jedis.incr(key);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return ret;
    }

    public Long getIncr(String key, int seconds) {
        ShardedJedis jedis = pool.getResource();
        Long ret = null;
        try {
            ShardedJedisPipeline shardedJedisPipeline = jedis.pipelined();
            shardedJedisPipeline.incr(key);
            shardedJedisPipeline.expire(key, seconds);
            List<Object> list = shardedJedisPipeline.syncAndReturnAll();
            ret = (Long) (list.get(0));
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return ret;
    }

    public Long pushSet(String key, String value, Integer seconds) {
        ShardedJedis jedis = pool.getResource();
        Long ret = Long.MAX_VALUE;
        try {
            ShardedJedisPipeline shardedJedisPipeline = jedis.pipelined();
            shardedJedisPipeline.sadd(key, value);
            shardedJedisPipeline.scard(key);
            if (seconds != null) shardedJedisPipeline.expire(key, seconds);
            List<Object> list = shardedJedisPipeline.syncAndReturnAll();
            ret = (Long) (list.get(0));
            if (ret != 0) {
                ret = (Long) (list.get(1));
            }
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return ret;
    }

    public Long pushSet(String key, Set<String> value, int seconds) {
        ShardedJedis jedis = pool.getResource();
        try {
            ShardedJedisPipeline shardedJedisPipeline = jedis.pipelined();
            for (String t : value)
                shardedJedisPipeline.sadd(key, t);
            shardedJedisPipeline.expire(key, seconds);
            shardedJedisPipeline.sync();
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return 1L;
    }

    public Long scardSet(String key) {
        ShardedJedis jedis = pool.getResource();
        Long ret = jedis.scard(key);
        jedis.close();
        return ret;
    }

    public Long getSetExistValue(String key, String value, int seconds) {
        ShardedJedis jedis = pool.getResource();
        Long ret = -1L;
        try {
            ShardedJedisPipeline shardedJedisPipeline = jedis.pipelined();
            shardedJedisPipeline.exists(key);
            shardedJedisPipeline.sismember(key, value);
            shardedJedisPipeline.expire(key, seconds);
            List<Object> list = shardedJedisPipeline.syncAndReturnAll();
            Boolean br = (Boolean) (list.get(0));
            if (br) {
                ret = ((Boolean) (list.get(1))) ? 1L : 0L;
            }
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return ret;
    }

    public Set<String> getSetValue(String key) {
        ShardedJedis jedis = pool.getResource();
        Set<String> set = null;
        try {
            set = jedis.smembers(key);
        } catch (Exception e) {
            logger.error("", e);
            e.printStackTrace();
        }
        jedis.close();
        return set;
    }

    public Long removeSetValue(String key, String value) {
        ShardedJedis jedis = pool.getResource();
        Long ret = jedis.srem(key, value);
        jedis.close();
        return ret;
    }

    public void pushRList(String key, String value) {
        ShardedJedis jedis = pool.getResource();
        jedis.rpush(key, value);
        jedis.close();
    }

    public void pushRListx(String key, String... value) {
        ShardedJedis jedis = pool.getResource();
        jedis.rpushx(key, value);
        jedis.close();
    }

    public String popLList(String key) {
        ShardedJedis jedis = pool.getResource();
        String string = jedis.lpop(key);
        jedis.close();
        return string;
    }

    public String hget(String key, String field) {
        ShardedJedis jedis = pool.getResource();
        String string = jedis.hget(key, field);
        jedis.close();
        return string;
    }

    public void hset(String key, String field, String value) {
        ShardedJedis jedis = pool.getResource();
        jedis.hset(key, field, value);
        jedis.close();
    }

    public void hremove(String key, String field) {
        ShardedJedis jedis = pool.getResource();
        jedis.hdel(key, field);
        jedis.close();
    }

    public void srem(String key, String value) {
        ShardedJedis jedis = pool.getResource();
        jedis.srem(key, value);
        jedis.close();
    }
}